/**
 * @Title: DynamicUtils.java
 * @Package com.ssd.demo.base.util
 * @Description: TODOo
 * @author xiaoruihu 2016年4月28日 下午2:58:38
 * @version V1.0
 */
package com.ssd.demo.base.util;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.HashSet;
import java.util.Set;

import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.core.type.filter.TypeFilter;
import org.springframework.util.ClassUtils;


/**
 * @Description: DynamicUtils
 * @author xiaoruihu 2016年4月28日 下午2:58:38
 */
public class DynamicUtils {

    private static final String RESOURCE_PATTERN = "/**/*.class";

    private static ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();

    /**
     * 将符合条件的class 注解
     * 
     * @return
     */
    public static Set<Class<?>> getClassSetAnnotation(String basePackage, Class<? extends Annotation> annotation) {
        return getClassSet(basePackage, new AnnotationTypeFilter(annotation, false));
    }

    /**
     * 将符合条件的class 子接口
     * 
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static Set<Class<?>> getClassSetSuperClass(String basePackage, Class<?> superClazz) {
        Set<Class<?>> set = getClassSet(basePackage, new AssignableTypeFilter(superClazz));
        set.remove(superClazz);
        return set;
    }

    /**
     * @Title: getActualType
     * @Description: 获取class的泛型class
     * @author xiaoruihu
     * @param clazz
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> Class<T> getClassActualTypeClass(Class<?> clazz) {
        Type genType = clazz.getGenericSuperclass();
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
        return (Class<T>) params[0];
    }
    
    /**
     * @Title: getActualType
     * @Description: 获取接口的泛型class
     * @author xiaoruihu
     * @param clazz
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> Class<T> getInterfafceActualTypeClass(Class<?> clazz) {
        Type genType = clazz.getGenericInterfaces()[0];
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
        return (Class<T>) params[0];
    }

    private static Set<Class<?>> getClassSet(String basePackage, TypeFilter tf) {
        Set<Class<?>> classSet = new HashSet<Class<?>>();
        try {
            String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(basePackage)
                    + RESOURCE_PATTERN;
            Resource[] resources = resourcePatternResolver.getResources(pattern);
            MetadataReaderFactory readerFactory = new CachingMetadataReaderFactory(resourcePatternResolver);
            for (Resource resource : resources) {
                if (resource.isReadable()) {
                    MetadataReader reader = readerFactory.getMetadataReader(resource);
                    String className = reader.getClassMetadata().getClassName();
                    if (tf.match(reader, readerFactory)) {
                        classSet.add(Class.forName(className));
                    }
                }
            }
            return classSet;
        }
        catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String args[]) throws IOException {

        // System.out.println(resources[0].getFile().getPath());
        //
        // for (Class<?> cl : set) {
        // System.out.println(cl.getName());
        // }
        //
        // Set<Class<?>> set2 = getClassSetSuperClass("com.ssd.demo",
        // BaseMapper.class);
        // System.out.println("----------");
        // for (Class<?> cl : set2) {
        // System.out.println(cl.getName());
        // System.out.println(getInterfafceActualTypeClass(cl).getName());
        // }

    }
}
